import BaseScene, { SceneConfig } from '../../components/scenes/BaseScene';
import * as THREE from 'three';
import {
  Color,
  CubeCamera,
  DoubleSide,
  Mesh,
  MeshNormalMaterial,
  PointLight,
  SphereBufferGeometry,
} from 'three';
import floor from '../../../textures/floors/FloorsCheckerboard_S_Diffuse.jpg';

/**
 * 反射的实现思路是：
 * 通过CubeCamera将该物体的视角生成一个图像，再将图像贴在物体上，实现的反射。
 */
class BasicScene extends BaseScene {
  mesh: Mesh;
  mirrorSphereCamera: CubeCamera;
  constructor(config) {
    super(config);
    const { camera } = this;
    this.addPlane();
    this.addLight();
    this.addOtherGeometry();
    this.addReflection();
    camera.position.setY(300);
    camera.position.setX(300);
    camera.position.setZ(300);
    camera.lookAt(0, 0, 0);
  }

  private addPlane() {
    const geometry = new THREE.PlaneBufferGeometry(1000, 1000, 100, 50);
    const material = new THREE.MeshBasicMaterial({
      side: THREE.BackSide,
    });
    const boxMesh = new THREE.Mesh(geometry, material);
    boxMesh.position.y = -60;
    boxMesh.rotation.x = -Math.PI / 2;

    const textureLoader = new THREE.TextureLoader();
    textureLoader.load(floor, function (map) {
      map.wrapS = THREE.RepeatWrapping;
      map.wrapT = THREE.RepeatWrapping;
      map.anisotropy = 16;
      map.repeat.set(5, 5);
      material.map = map;
      material.side = DoubleSide;
      material.needsUpdate = true;
    });
    boxMesh.receiveShadow = true;
    this.scene.add(boxMesh);
  }

  private addOtherGeometry() {
    const { scene } = this;
    const geometry = new SphereBufferGeometry(100, 32, 16);
    const mesh = new Mesh(
      geometry,
      new MeshNormalMaterial({ transparent: true, opacity: 0.7 })
    );
    mesh.castShadow = true;
    mesh.position.setX(-300);
    mesh.position.setY(50);
    scene.add(mesh);
    const outlineMaterial1 = new THREE.MeshBasicMaterial({
      color: 0xff0000,
      opacity: 0.5,
      transparent: true, //注意，此处必须设置为开启透明
      side: THREE.BackSide,
    });
    const outlineMesh1 = new THREE.Mesh(geometry, outlineMaterial1);
    outlineMesh1.position.set(
      mesh.position.x,
      mesh.position.y,
      mesh.position.z
    );
    outlineMesh1.scale.multiplyScalar(1.05);
    scene.add(outlineMesh1);
  }
  private addReflection() {
    const { scene } = this;
    scene.background = new Color(0xffffff);
    //构建网格
    const geometry = new SphereBufferGeometry(50, 50, 50);
    const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256, {
      format: THREE.RGBFormat,
      generateMipmaps: true,
      minFilter: THREE.LinearMipmapLinearFilter,
    });
    //构建相机
    const mirrorSphereCamera = new THREE.CubeCamera(0.1, 500, cubeRenderTarget);
    scene.add(mirrorSphereCamera);
    //将相机的生成的target.texture传递给网格材质。
    const mirrorSphereMaterial = new THREE.MeshBasicMaterial({
      color: 0xffffff,
      transparent: true,
      opacity: 0.7,
      envMap: cubeRenderTarget.texture,
      refractionRatio: 1, //调节反射率
      reflectivity: 1,// 调节反射的清晰度
    });
    const mesh = new Mesh(geometry, mirrorSphereMaterial);
    mirrorSphereCamera.position.copy(mesh.position);
    scene.add(mesh);
    this.mesh = mesh;
    this.mirrorSphereCamera = mirrorSphereCamera;
  }
  public run() {
    const { scene, mesh, mirrorSphereCamera } = this;
    if (mesh) {
      //在cube相机更新前，先隐藏掉网格
      this.mesh.visible = false;
      mirrorSphereCamera.update(this.renderer, scene);
      this.mesh.visible = true;
    }
    super.run();
  }
  private addLight() {
    const { scene, renderer } = this;
    const light = new PointLight(0xffffff, 0.7);
    light.castShadow = true;
    light.position.setY(300);
    scene.add(light);
    scene.add(new THREE.PointLightHelper(light, 10));
    renderer['shadowMapEnabled'] = true;
  }
}

export const render = (config: SceneConfig): BasicScene => {
  const renderWater = new BasicScene(config);
  renderWater.run();
  return renderWater;
};
